#include "StdAfx.h"
#include "Character.h"
#include "PhysX.h"
#include "GraphCamera.h"
#include "NxController.h"
#include "PhysX.h"
#include "Key.h"
#include <boost/foreach.hpp>

Character::Character(GraphCamera* pGraphCamera,D3DXVECTOR3 start,PhysX* pPhysX):
	m_pCamera(pGraphCamera),
	m_PosW(start),
	m_pPhysX(pPhysX),
	m_ammoCount(120),
	m_RunningMultiplicationFactor(2.5f),m_Speed(5.0f),m_MouseScale(100),m_Radius(.8f),m_Height(3.0f)
{
	m_pController = m_pPhysX->CreateController(this);
}

Character::~Character(void)
{
	if ( m_pCamera !=  0 )
		delete m_pCamera;
	
	vector<Key*>::iterator it;
	for ( it = m_Inventory.begin(); it != m_Inventory.end(); ++it){
		delete *it;
	}
}

tstring Character::GetContactShape()
{
	NxRay ray(NxVec3(m_PosW.x,m_PosW.y,m_PosW.z), NxVec3(0,-1,0));
	NxShape* HitShape = 0;

	HitShape = m_pPhysX->GetClosestShape(ray, 4.5f);
	if(HitShape == 0)
	{
		if(HitShape->getName() != 0)
		{
			string s(HitShape->getName());
			tstring ts(s.begin(), s.end());

			return ts;
		}
		return _T("shape found");
	} else {
		return _T("No shape");
	}
}

bool Character::HasContact()
{
	NxRay ray(NxVec3(m_PosW.x,m_PosW.y,m_PosW.z), NxVec3(0,-1,0));
	NxShape* HitShape = 0;

	HitShape = m_pPhysX->GetClosestShape(ray, 4.5f);

	if(HitShape != 0)
	{
		return true;
	}
	
	return false;
}

void Character::Tick(const InputState& state){
	XBoxController* controller = state.GetController();
	if(!controller->IsControllerConnected(0))
	{
		bool bRunning=false;
		// Find the net direction the camera is traveling in (since the
		// camera could be running and strafing).

		D3DXVECTOR3 dir(0.0f, 0.0f, 0.0f);
		if(state.IsKeyDown('Z') )
			dir += m_pCamera->GetLook();
		if(state.IsKeyDown('S') )
			dir -= m_pCamera->GetLook();
		if(state.IsKeyDown('D') )
			dir += m_pCamera->GetRight();
		if(state.IsKeyDown('Q') )
			dir -= m_pCamera->GetRight();
		if(state.IsKeyDown(VK_LSHIFT) )
			bRunning = true;
	
		// Move at mSpeed along net direction.
		D3DXVec3Normalize(&dir, &dir);
		float finalspeed = m_Speed;
		if(bRunning)finalspeed*=m_RunningMultiplicationFactor;
		//use dt so that speed is independent from framerate 
		dir *= finalspeed*state.GetDeltaTime();
		if ( dir.y > 0 )
			dir.y = 0;

		NxU32 flags;

	
		if ( state.GetDeltaTime() > 0.001f)
		{
			if ( !HasContact() ){
				// add gravity code.
				D3DXVECTOR3 diff = m_PosW - m_PreviousPosW;

				float vy = diff.y / state.GetDeltaTime();

				vy += (-9.82f * state.GetDeltaTime());
				dir.y += vy * state.GetDeltaTime();
			}
		}
		NxVec3 disp(dir.x, dir.y, dir.z);
		flags = NXCC_COLLISION_SIDES;

		m_pController->move(disp, 1, 0, flags);

		m_PreviousPosW = m_PosW;
		NxVec3 NewPos;
		NewPos = m_pController->getActor()->getGlobalPosition();
		m_PosW.x = NewPos.x;
		m_PosW.y = NewPos.y;
		m_PosW.z = NewPos.z;

		if(state.IsLeftMouseButtonDown())
		{
			float MousePitch = state.GetMouseMovement().y / m_MouseScale;
			float MouseRotate = state.GetMouseMovement().x / m_MouseScale;
			m_pCamera->Move(m_PosW, true, MousePitch, MouseRotate);
		} else {
			m_pCamera->Move(m_PosW);
		}
	}else{
		bool bRunning=false;
		// Find the net direction the camera is traveling in (since the
		// camera could be running and strafing).

		D3DXVECTOR3 dir(0.0f, 0.0f, 0.0f);
		if(controller->IsControllerButtonPressed(0, XINPUT_GAMEPAD_DPAD_UP))
			dir += m_pCamera->GetLook();
		if(controller->IsControllerButtonPressed(0, XINPUT_GAMEPAD_DPAD_DOWN))
			dir -= m_pCamera->GetLook();
		if(controller->IsControllerButtonPressed(0, XINPUT_GAMEPAD_DPAD_RIGHT))
			dir += m_pCamera->GetRight();
		if(controller->IsControllerButtonPressed(0, XINPUT_GAMEPAD_DPAD_LEFT))
			dir -= m_pCamera->GetRight();

		float magnitude = 0;
		float RightnormX = 0;
		float RightnormY = 0;
		if(controller->IsControllerButtonPressed(0,XINPUT_GAMEPAD_LEFT_SHOULDER)) bRunning = true;

		controller->GetInputFromRightThumbStick(0,magnitude,RightnormX,RightnormY);
		float xAngle = RightnormY * (magnitude * -1)/ m_MouseScale;
		float yAngle = RightnormX * magnitude / m_MouseScale;

		// Move at mSpeed along net direction.
		D3DXVec3Normalize(&dir, &dir);
		float finalspeed = m_Speed;
		if(bRunning)finalspeed*=m_RunningMultiplicationFactor;
		//use dt so that speed is independent from framerate 
		dir *= finalspeed*state.GetDeltaTime();
		if ( dir.y > 0 )
			dir.y = 0;

		NxU32 flags;

	
		if ( state.GetDeltaTime() > 0.001f)
		{
			if ( !HasContact() ){
				// add gravity code.
				D3DXVECTOR3 diff = m_PosW - m_PreviousPosW;

				float vy = diff.y / state.GetDeltaTime();

				vy += (-9.82f * state.GetDeltaTime());
				dir.y += vy * state.GetDeltaTime();
			}
		}
		NxVec3 disp(dir.x, dir.y, dir.z);
		flags = NXCC_COLLISION_SIDES;

		m_pController->move(disp, 1, 0, flags);

		m_PreviousPosW = m_PosW;
		NxVec3 NewPos;
		NewPos = m_pController->getActor()->getGlobalPosition();
		m_PosW.x = NewPos.x;
		m_PosW.y = NewPos.y;
		m_PosW.z = NewPos.z;

		m_pCamera->Move(m_PosW, true, xAngle, yAngle);
	}
}

void Character::SetMouseScale(int scale)
{
	if(scale>1 && scale<1000)
		m_MouseScale = (float)scale;
}

bool Character::HasKey(int id)
{
	BOOST_FOREACH(Key* item, m_Inventory)
	{
		if(item->GetID() == id)
			return true;
	}
	return false;
}
